package jp.tkym.labs.store;

import jp.tkym.labs.util.prop.PropertyResolver;
import jp.tkym.labs.util.prop.PropertyResolverProvider;

import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;

public class KeyFactoryUnit<B>{
	private PropertyResolver<B> resolver;
	private String kind;
	private Key parent;
	private String keyProperty;
	private String idProperty;
	private Class<B> cls;
	
	KeyFactoryUnit(Key parent, Class<B> cls, String idProperty, String keyProperty){
		this.cls = cls;
		this.resolver = PropertyResolverProvider.getInstance().get(cls);
		this.kind = cls.getSimpleName();
		this.parent = parent;
		this.keyProperty = keyProperty;
		this.idProperty = idProperty;
		checkConstructorsArgument();
	}
	
	private void checkConstructorsArgument(){
		if(keyProperty != null) checkKeyProperty();
		if(idProperty != null) checkIdProperty();
		if(keyProperty == null && idProperty == null)
			throw new IllegalArgumentException(
					"Both idProperty and keyProperty are null "
			);
	}
	
	private void checkIdProperty(){
		if(!resolver.contains(idProperty)){
			String msg = "idProperty[" + idProperty + "] is not contains of class [" + cls.getName() + "]";
			throw new IllegalArgumentException(msg);
		}
		if(!resolver.getTypeOf(idProperty).equals(long.class)){
			String msg = "idProperty[" + idProperty + "] of class[" + cls.getName() +" is unsupport Type [" + cls.getName() + "]";
			throw new IllegalArgumentException(msg);
		}
	}
	
	private void checkKeyProperty(){
		if(!resolver.contains(keyProperty)){
			String msg = "keyProperty[" + keyProperty + "] is not contains of class [" + cls.getName() + "]";
			throw new IllegalArgumentException(msg);
		}
		if(!resolver.getTypeOf(keyProperty).equals(long.class)){
			String msg = "keyProperty[" + keyProperty + "] of class[" + cls.getName() +" is unsupport Type [" + cls.getName() + "]";
			throw new IllegalArgumentException(msg);
		}
	}
	
	public B bean(Key key){
		B bean = resolver.createInstance();
		Class<?> type = resolver.getTypeOf(keyProperty);
		resolver.set(bean, keyProperty, toValue(type, key));
		return bean;
	}
	
	Object toValue(Class<?> type, Key key){
		if(ValueConverterForDatastore.isStringValue(type))
			return ValueConverterForDatastore.fromDatastore(type, key.getName());
		if(ValueConverterForDatastore.isLongValue(type))
			return ValueConverterForDatastore.fromDatastore(type, key.getId());
		throw new IllegalArgumentException(type.getName()+" is not supported");
	}
	
	public Key keyOf(B bean){
		Object value = resolver.get(bean, this.keyProperty);
		return key(value);
	}
	
	Key key(Object value){
		Class<?> keyType = value.getClass();
		if(ValueConverterForDatastore.isLongValue(keyType))
			return create(ValueConverterForDatastore.toLongForDatastore(keyType, value));
		if(ValueConverterForDatastore.isStringValue(keyType))
			return create(ValueConverterForDatastore.toStringForDatastore(keyType, value));
		throw new IllegalArgumentException(keyType.getName()+" is not supported");
	}
	
	Key create(String name){
		return KeyFactory.createKey(parent, kind, name);
	}
	
	Key create(long id){
		return KeyFactory.createKey(parent, kind, id);
	}
}